using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace BepuUtilities.Memory
{
    /// <summary>
    /// 带有一些帮助器的原始字节缓冲区,用于与类型化范围进行互操作。
    /// </summary>
    public unsafe struct RawBuffer : IEquatable<RawBuffer>
    {
        public byte* Memory;
        public int Length;
        // 我们主要对x64感兴趣,所以内存+长度是12字节。无论如何出于对齐原因,该结构将/应该被填充到16字节,
        // 因此,利用最后4个字节来加速从池中获取原始缓冲区的情况(基本上总是如此)是一个很好的选择。

        /// <summary>
        /// 由源设置的原始缓冲区的实现特定标识符。如果从BufferPool中获取,则ID表示从中获取的打包电源和内部电源池索引。
        /// </summary>
        public int Id;

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public RawBuffer(void* memory, int length, int id = -1)
        {
            Memory = (byte*)memory;
            Length = length;
            Id = id;
        }

        public bool Allocated
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                return Memory != null;
            }
        }

        public ref byte this[int index]
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                return ref *(Memory + index);
            }
        }

        /// <summary>
        /// 将内存位置处的字节解释为给定类型。
        /// </summary>
        /// <typeparam name="T">键入以将内存解释为。</typeparam>
        /// <param name="byteIndex">要解释的内存位置。</param>
        /// <return>作为给定类型对内存的引用。</return>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public ref T Interpret<T>(int byteIndex)
        {
            ValidateRegion(byteIndex, Unsafe.SizeOf<T>());
            return ref Unsafe.As<byte, T>(ref *(Memory + byteIndex));
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public RawBuffer Slice(int start, int count)
        {
            ValidateRegion(start, count);
            return new RawBuffer(Memory + start, count, Id);
        }

        /// <summary>
        /// 将原始缓冲区的一个区域作为类型化缓冲区。
        /// </summary>
        /// <typeparam name="T">键入以将区域解释为。</typeparam>
        /// <param name="start">以类型大小表示的区域起始位置。</param>
        /// <param name="count">按类型表示的区域中的元素数。</param>
        /// <return>类型化缓冲区。</return>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public Buffer<T> Slice<T>(int start, int count) where T : unmanaged
        {
            ValidateRegion<T>(start, count);
            return new Buffer<T>(Memory + start * Unsafe.SizeOf<T>(), count * Unsafe.SizeOf<T>(), Id);
        }

        /// <summary>
        /// 从原始缓冲区创建可容纳在分配的字节内的最大容量的类型化区域。
        /// </summary>
        /// <typeparam name="T">缓冲区的类型。</typeparam>
        /// <return>当前原始缓冲区内最大范围的类型化缓冲区。</return>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public Buffer<T> As<T>() where T : unmanaged
        {
            var count = Length / Unsafe.SizeOf<T>();
            return new Buffer<T>(Memory, count, Id);
        }


        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void Clear(int start, int count)
        {
            Unsafe.InitBlockUnaligned(Memory + start, 0, (uint)count);
        }

        // 待办事项：一些副本可能会有帮助,但让我们等到真正需要它们时再做。

        [Conditional("DEBUG")]
        void ValidateRegion<T>(int startInElements, int countInElements)
        {
            Debug.Assert(startInElements * Unsafe.SizeOf<T>() >= 0, "The start of a region must be within the buffer's extent.");
            Debug.Assert((startInElements + countInElements) * Unsafe.SizeOf<T>() <= Length, "The end of a region must be within the buffer's extent.");
        }

        [Conditional("DEBUG")]
        void ValidateRegion(int start, int count)
        {
            Debug.Assert(start >= 0, "The start of a region must be within the buffer's extent.");
            Debug.Assert(start + count <= Length, "The end of a region must be within the buffer's extent.");
        }

        // 它们主要用于缓冲池中的调试目的。
        public override unsafe int GetHashCode()
        {
            if (IntPtr.Size == 4)
            {
                var temp = Memory;
                return *((int*)&temp);
            }
            else
            {
                var temp = Memory;
                return (*((long*)&temp)).GetHashCode();
            }
        }

        public bool Equals(RawBuffer other)
        {
            return other.Memory == Memory && other.Length == Length;
        }

        public override bool Equals(object obj)
        {
            if (obj is RawBuffer buffer)
                return Equals(buffer);
            return false;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static implicit operator Span<byte>(in RawBuffer buffer)
        {
            return new Span<byte>(buffer.Memory, buffer.Length);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static implicit operator ReadOnlySpan<byte>(in RawBuffer buffer)
        {
            return new ReadOnlySpan<byte>(buffer.Memory, buffer.Length);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static implicit operator Buffer<byte>(in RawBuffer buffer)
        {
            return new Buffer<byte>(buffer.Memory, buffer.Length);
        }

    }
}
